//
//  UserPreferenceManager.swift
//  YoruNeko
//
//  Created by liphone on 2021/6/17.
//

import Foundation
import UIKit
/**
 用户信息设置管理类
 预制了许多getter与setter方法，每次setter之后如果需要持久存储，则需要调用commit()（可能会阻塞）
 */
class UserPreferenceManager{
    
    
    /*
     相关设置格式:
     使用该类时可以参考，但不会直接操作设置树, 设置树中，每个键值均可以通过SettingKey枚举变量获取
{
     "user_list":[
        "anouymous",...,
     ]
     "anouymous":{
        
     },
     "user_uuid_1":{
     //
         "modified_time":"" //表示写入存储的时间
         "current_engine_index":0
         
         "home":{
         
             "current_home_index":0,
             "home_list":[{
             "title":"Yoruneko首页",
             "url":null
             }]
         },
         
         "download_setting":{
            "download_alert":true
         },
         "user":{
             "name":"anouymous",
             "sync":true,
             "image":null,
         }
    }
     
}
     
     */
    
    /**
     通过该方法获取对应uuid的用户偏好管理器。
     */
    static func manager(of userUuid:UUID?)->UserPreferenceManager{
        
        var uuid:String
        if userUuid == nil  {
            uuid = anonymous
        }
        else{
            uuid = userUuid!.uuidString
            addUserConfiguration(user_uuid: userUuid!)
        }
        
        return UserPreferenceManager.init(user_token: uuid)
        
    }
    
    /**
     返回可用的用户列表，数组中保存用户uuid, 该列表不会为空，它总会有anouymous用户
     */
    static func getAvailableUsers()->[String]{
        let userPrefs = UserDefaults.standard
        
        
        var userList = [String].init()
        if let array = userPrefs.stringArray(forKey: SettingKey.userListKey.rawValue) {
            
            var iterator = array.makeIterator();
            var next = iterator.next()
            
            while(next != nil){
                userList.append(next!)
                next = iterator.next()
            }
    
        }
        
        if userList.isEmpty {
            userList.append(anonymous)
        }
        
        return userList
        
    }
    
    static private func addUserConfiguration(user_uuid:UUID){
        var userList = getAvailableUsers()
        if !userList.contains(user_uuid.uuidString) {
            YRNKLog("UserPreferenceManager", msg: "user[\(user_uuid.uuidString)] doesn't exist and prepare to create")
            //prepare to add to userDefault
            let userDefault = UserDefaults.standard
            userList.append(user_uuid.uuidString)
            userDefault.set(userList, forKey: SettingKey.userListKey.rawValue)
            YRNKLog("UserPreferenceManager", msg: "insert user[\(user_uuid.uuidString)]")
        }
    }
    
    /**
     提交当前所有的set函数的更改, 可能会阻塞，可以放到工作线程中执行
     */
    func commit(){
        lock.lock()
        self.prefsCache.modified_time = NSDate.init()
        YRNKLog("manager of user[\(keyDomain)]", msg: "commit changed")
        userPrefs.set(self.prefsCache.toDict(), forKey: keyDomain)
        lock.unlock()
    }
    
    /**
     设置用户名 Nickname
     */
    func setUsername(nickname:String){
        prefsCache.user_name = nickname
    }
    
    func setUserAvatar(image:UIImage){
        
        if let data = image.pngData() {
            prefsCache.image = try? NSData.init(data: data).compressed(using: .lzma)
        }
        
        else if let data = image.jpegData(compressionQuality: 0.617) {
            prefsCache.image = try? NSData.init(data:data).compressed(using: .lzma)
        }
        
    }
    
    
    func setUserMail(mail:String){
        prefsCache.mail = mail
    }
    
    /**
     index 参数未检查是否越界，index 记录了搜索引擎列表中所选中引擎的偏移量
     */
    func setSearchEngineSelectIndex(index: Int ){
        prefsCache.current_engine_index = index
    }
    
    
//    func setSearchEngineList(list:[[String:Any?]]){
//        prefsCache.engines_list = list
//    }
    
    func setHomeSelectIndex(index:Int){
        prefsCache.current_home_index = index
    }
    
    func setHomeList(list:[[String:Any?]]){
        prefsCache.home_list = list
    }
    
    func setSync(sync:Bool){
        prefsCache.sync = sync
    }
    
    func setDownloadAlert(alert:Bool){
        prefsCache.download_alert = alert
    }
    
    func setNoHistory(isNo: Bool) {
        prefsCache.noHistory = isNo
    }
    
    func getNoHistory() -> Bool {
        return prefsCache.noHistory
    }
    
    func getSync()->Bool{
        return prefsCache.sync
    }
    
    func getUsername()->String{
        return prefsCache.user_name
    }
    
    func getSearchEngineSelectIndex()->Int{
        return prefsCache.current_engine_index
    }
    
    /**
     获取当前主页选中的索引号
     */
    func getHomeSelectIndex()->Int{
        return prefsCache.current_home_index
    }
    

//    func getSearchEngineList()->[[String:Any?]]{
//        return prefsCache.engines_list
//    }
    
    
    /**
     获取一个列表，列表项均为字典，通过SettingKey 查询每个列表项中存在的属性值
     一般这里只有两个属性值，title，url：URL
     */
    func getHomeList()->[[String:Any?]]{
        return prefsCache.home_list
    }
    
    func getModifiedTime()->NSDate?{
        return prefsCache.modified_time
    }
    
    func getDownloadAlert()->Bool{
        return prefsCache.download_alert
    }
    
    func getUserMail()->String{
        return prefsCache.mail
    }
    
    
    func getUserAvatar()->UIImage?{
        guard let imageNSData = prefsCache.image else{
            return nil
        }
        
        guard let imageUncompressedData = try? imageNSData.decompressed(using: .lzma) else {
            YRNKLog(self.description, msg: "try to uncompressed data failed ")
            return nil
        }
        
        let img_data = Data.init(referencing: imageUncompressedData)
        
        return UIImage.init(data: img_data)
    }
    
    func deleteThis(){
        userPrefs.removeObject(forKey: keyDomain)
    }
    
    private init(user_token: String){
        keyDomain = user_token
        prefsCache = PrefsCache.init()
        cacheIn()
    }
    

    private func cacheIn(){
        
        
        //set time
        prefsCache.modified_time = self._getModifiedTime()
        if let index = self._getSearchEngineSetting()[SettingKey.currentIndexKey.rawValue] as? Int{
            prefsCache.current_engine_index = index
        }

        if let index = self._getHomeSetting()[SettingKey.currentIndexKey.rawValue] as? Int {
            prefsCache.current_home_index = index
        }
        if let list = self._getHomeSetting()[SettingKey.listKey.rawValue] as? [[String:Any?]] {
            prefsCache.home_list = list
        }
        
        if let alert = self._getDownloadSetting()[SettingKey.downloadAlertKey.rawValue] as? Bool {
            prefsCache.download_alert = alert
        }
        
        let user_setting = self._getUserSetting()
        
        if let username = user_setting[SettingKey.nameKey.rawValue] as? String {
            prefsCache.user_name = username
        }
        if let sync = user_setting[SettingKey.syncKey.rawValue] as? Bool {
            prefsCache.sync = sync
        }
        
        if let imageData = user_setting[SettingKey.imageKey.rawValue] as? NSData{
            prefsCache.image = imageData
        }
        
        if let mail = user_setting[SettingKey.mailKey.rawValue] as? String{
            prefsCache.mail = mail
        }
        
        prefsCache.noHistory = _getNoHistory()
        
    }
    
    /**
     获取download设置
     */
    private func _getDownloadSetting()->[String:Any?]{
        let md = _getMainDomain()
        if let setting = md[SettingKey.downloadSettingKey.rawValue] as? [String:Any?]{
            return setting
        }
        else{
            return [SettingKey.downloadAlertKey.rawValue:true]
        }
        
    }
    
    private func _getNoHistory()->Bool{
        let md = _getMainDomain()
        if let noHistory = md[SettingKey.noHistoryKey.rawValue] as? Bool{
            return noHistory
        }
        else{
            return false;
        }
    }
    
    private func _getModifiedTime()->NSDate?{
        return _getMainDomain()[SettingKey.modifiedTimeKey.rawValue] as? NSDate
    }
    
    private func _getHomeSetting()->[String:Any?] {
        let md = _getMainDomain()
        if let setting = md[SettingKey.homeKey.rawValue] as? [String:Any?]{
            return setting
        }
        else{
            return [
                SettingKey.currentIndexKey.rawValue:0,
                SettingKey.listKey.rawValue:[]
            ]
        }
        
        
    }
    
    private func _getSearchEngineSetting()->[String:Any?] {
        let md = _getMainDomain()
        if let setting = md[SettingKey.searchEnginesSettingKey.rawValue] as? [String:Any?] {
            return setting
        }
        else{
            return [
                SettingKey.currentIndexKey.rawValue:0,
                SettingKey.listKey.rawValue:[]
            ]
        }
    }
    
    private func _getMainDomain()->[String:Any?]{
        if let md = userPrefs.object(forKey: keyDomain) as? [String:Any?]{
            return md
        }
        else{
            return [SettingKey.modifiedTimeKey.rawValue:nil,
                    SettingKey.searchEnginesSettingKey.rawValue:[
                        SettingKey.currentIndexKey.rawValue:0,
                        SettingKey.listKey.rawValue:[]
                    ],
                    SettingKey.noHistoryKey.rawValue: false,
                    SettingKey.homeKey.rawValue:[
                        SettingKey.currentIndexKey.rawValue:0,
                        SettingKey.listKey.rawValue:[]
                    ],
                    SettingKey.downloadSettingKey.rawValue:[SettingKey.downloadAlertKey.rawValue:true],
                    SettingKey.userKey.rawValue:[
                        SettingKey.nameKey.rawValue:keyDomain,
                        SettingKey.syncKey.rawValue:true,
                        SettingKey.imageKey.rawValue:nil
                    ]
            ]
        }
    }
    
    private func _getUserSetting()->[String:Any?]{
        let md = _getMainDomain()
        if let setting = md[SettingKey.userKey.rawValue] as? [String:Any?]{
            return setting
        }
        else{
            return [
                SettingKey.nameKey.rawValue:keyDomain,
                SettingKey.syncKey.rawValue:true,
                SettingKey.imageKey.rawValue:nil,
            ]
        }
    }
    
    //更细粒度的get函数
    private func _getUserName()->String{
        let setting = _getUserSetting()
        if let name = setting[SettingKey.nameKey.rawValue] as? String{
            return name
        }
        else{
            //should not happen!
            return keyDomain
        }
    }
    
    private func _getUserImage()->UIImage{
        //获取一个默认的image
        let setting = _getUserSetting()
        if let imageNSData = setting[SettingKey.imageKey.rawValue] as? NSData {
            let data = Data.init(referencing: imageNSData)
            if let image = UIImage.init(data: data){
                return image
            }
        }
        return UIImage(systemName: "person")!
    }
    
    //    func setUserImage(image:UIImage){
    //        var md = getMainDomain()
    //    }
    
    var description :String  {"UserPreferenceManager[\(self.keyDomain)]"}
    
    
    //some fast reference, when need just .
    enum SettingKey:String{
        case downloadSettingKey="download_setting"
        case userKey="user"
        case homeKey="home"
        case modifiedTimeKey="modified_time"
        case searchEnginesSettingKey="search_engine_setting"
        case currentIndexKey="index"
        case listKey="list"
        case titleKey="title"
        case urlKey="url"
        case downloadAlertKey="download_alert"
        case nameKey="name"
        case syncKey="sync"
        case imageKey="image"
        case mailKey="mail"
        case userListKey="user_list"
        case noHistoryKey="no_history"
    }
    private let keyDomain:String
    private var prefsCache:PrefsCache
    private let lock = NSLock.init()
    
    let userPrefs = UserDefaults.standard
    static let anonymous = "anonymous"
    
    
    //对设置信息的缓存对象
    private class PrefsCache{
        var modified_time:NSDate?
        var current_engine_index = 0
        
        var current_home_index = 0
        var home_list:[[String:Any?]]=[]
        
        var download_alert = true
        var user_name = "anonymous"
        var sync=true
        var image:NSData?
        var mail=""
        var noHistory = false
        
        func toDict()->[String:Any?]{
            
            var user_v:[String:Any]

            if image != nil {
                user_v = [
                        SettingKey.nameKey.rawValue:user_name,
                        SettingKey.mailKey.rawValue:mail,
                        SettingKey.syncKey.rawValue:sync,
                        SettingKey.imageKey.rawValue:image,
                    ] as [String:Any]
            }
            else{
                user_v = [SettingKey.nameKey.rawValue:user_name,SettingKey.mailKey.rawValue:mail,SettingKey.syncKey.rawValue:sync] as [String : Any]
            }
            
            
            
            return [
                SettingKey.modifiedTimeKey.rawValue:modified_time,
                SettingKey.searchEnginesSettingKey.rawValue:[SettingKey.currentIndexKey.rawValue:current_engine_index],
                SettingKey.noHistoryKey.rawValue: noHistory,
                SettingKey.homeKey.rawValue:[
                   SettingKey.currentIndexKey.rawValue:current_home_index,
                    SettingKey.listKey.rawValue:home_list
                ],
                SettingKey.downloadSettingKey.rawValue:[SettingKey.downloadAlertKey.rawValue:download_alert],
                
                SettingKey.userKey.rawValue:user_v
            ]
        }
        
    }
}
